package com.talkyun.utils.download;

import com.talkyun.utils.MD5;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import static java.net.HttpURLConnection.HTTP_OK;

/**
 * @author kevin
 */
public class FastLoader {
    private static final Logger logger = LoggerFactory.getLogger(FastLoader.class);
    private static final int HTTP_TIMEOUT = 3 * 1000;
    private int threadNum;

    private URL url;
    private String localFilePath;

    public FastLoader(String urls, String localFilePath, int threadNum) {
        this.threadNum = threadNum;
        try {
            this.url = new URL(urls);
        } catch (MalformedURLException e) {
            throw new RuntimeException(e);
        }
        this.localFilePath = localFilePath;
    }

    public void load() throws IOException {
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("HEAD");
        conn.setReadTimeout(HTTP_TIMEOUT);
        conn.setConnectTimeout(HTTP_TIMEOUT);

        if (conn.getResponseCode() != HTTP_OK) {
            throw new IOException("Http response code error! " + conn.getResponseCode());
        }

        // 获取到请求资源文件的长度
        int length = conn.getContentLength();
        String md5 = conn.getHeaderField("Content-MD5");
        logger.info("Total length: " + length + ", " + url);

        // 创建随机存储文件
        File tmpFile = new File(localFilePath + ".loading");
        if (tmpFile.exists()) {
            if (tmpFile.delete()) {
                logger.info("Delete old loading file. {} ", tmpFile.getAbsolutePath());
            }
        }
        RandomAccessFile raf = new RandomAccessFile(tmpFile, "rwd");
        raf.setLength(length);
        raf.close();

        this.doMulThreadDown(tmpFile.getAbsolutePath(), threadNum, length);

        // check md5
        if (md5 == null || md5.equalsIgnoreCase(MD5.md5FileToBase64(tmpFile.getAbsolutePath()))) {
            File localFile = new File(localFilePath);
            if (localFile.exists()) {
                if (localFile.delete()) {
                    logger.error("File exists, delete first! {}", localFilePath);
                }
            }
            if (!tmpFile.renameTo(new File(localFilePath))) {
                logger.error("Can't rename file! {}", tmpFile.getAbsolutePath());
                throw new RuntimeException("Rename exception! " + tmpFile.getAbsolutePath() + " to " + localFilePath);
            }
            logger.info("Load url success! {} ", localFilePath);
        } else {
            logger.error("Md5 not match! ");
            throw new RuntimeException("Md5 not match! ");
        }
    }

    private void doMulThreadDown(String file, int threadNum, int totalSize) {
        int size = totalSize / threadNum;
        Thread[] pool = new Thread[threadNum];

        for (int i = 0; i < threadNum; i++) {
            // startIndex, endIndex 分别代表线程的开始和结束位置
            int startIndex = i * size;
            int endIndex = (i + 1) * size - 1;
            if (i == threadNum - 1) {
                // 如果是最后一个线程，那么结束位置写死
                endIndex = totalSize - 1;
            }
            Thread task = new DownTask(url.toString(), file, startIndex, endIndex, i);
            task.start();
            pool[i] = task;
        }

        for (Thread t : pool) {
            try {
                t.join();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public static void main(String[] args) throws IOException {
        String url = "http://yf-example.oss-cn-shenzhen.aliyuncs.com/webtest/daemon-pos/tomcat.zip";

        new FastLoader(url, "./tmp.zip", 4).load();
    }

}